﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Web;
using System.IO;
using System.Diagnostics;

using RAFOJ.Structs;

namespace RAFOJ.Submitters
{
    class SPOJSubmitter : Submitter
    {
        // Constants
        const string submitURL = "http://www.spoj.pl/submit/complete/";
        const string statusURL = "http://www.spoj.pl/status/";

        // Constructor
        public SPOJSubmitter() : base("SPOJ")
        {

        }

        // Methods

        public void submit(Submission submission)
        {

            Thread thread = new Thread(() => work(submission));
            thread.Start();
        }

        private void work(Submission submission)
        {
            int idx = getIdleClient();
            submissions[idx] = submission;

            createHttpRequest(idx, createSPOJPostData(idx), submitURL);
            getResult(idx);
            updateStandings(idx);
            waitForUnfreeze(idx, 3000);
        }

        public void getResult(int idx)
        {
            Console.WriteLine("Getting result for " + usernames[idx] + "...");

            Stopwatch sw = new Stopwatch();
            sw.Start();
            long cur = sw.ElapsedMilliseconds;
            int sleepInterval = 2000;

            while (sw.ElapsedMilliseconds - cur < 10000)
            {
                HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("http://www.spoj.pl/status/" + usernames[idx]);
                httpRequest.Method = "GET";

                using (HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse())
                {
                    Stream dataStream = response.GetResponseStream();

                    // Open the stream using a StreamReader for easy access.
                    StreamReader reader = new StreamReader(dataStream);

                    // Read the content.
                    string responseFromServer = reader.ReadToEnd();

                    // Get submission id
                    int submission_id = parseSubmissionId(responseFromServer);

                    // Get submission status
                    submissions[idx].setStatus(parseSubmissionStatus(responseFromServer, submission_id));

                    // Get error info of the submission
                    submissions[idx].setErrorInfo(getErrorInfo(idx, submission_id));

                    // Cancel current http request
                    httpRequest.Abort();

                    if (!submissions[idx].getStatus().Contains("ing"))
                    {
                        return;
                    }
                }

                TimeSpan timeSpan = new TimeSpan(0, 0, 0, 0, sleepInterval);
                Thread.Sleep(timeSpan);

                sleepInterval += 500;
            }
            sw.Stop();
        }

        private string getErrorInfo(int idx, int submission_id)
        {
            if (submissions[idx].getStatus() != "Compilation error") return "";

            // get content of the: "http://www.spoj.pl/error/" + submission_id
            string[] data = { "login_user=" + usernames[idx], "password=" + passwords[idx] };
            string postData = createPostData(data);
            string responseFromServer = createHttpRequest(idx, createPostData(data), "http://www.spoj.pl/error/" + submission_id);

            // Parsing error info
            // Get starting possition
            int p = responseFromServer.IndexOf("<small>", responseFromServer.IndexOf("<td class=\"content\" width=\"99%\"")) + "<small>".Length;

            // While current character is not '<' add character to result
            string result = "";
            while (responseFromServer[p] != '<')
            {
                result += responseFromServer[p++];
            }

            return HttpUtility.HtmlDecode(result);
        }

        /**
         * Returns result of the current submission
         */
        private string parseSubmissionStatus(string responseFromServer, int submission_id)
        {
            int p = responseFromServer.IndexOf("id=\"statusres_" + submission_id + "\"");
            while (responseFromServer[p] != '>') p++;
            p++;
            string result = "";
            while (responseFromServer[p] != '<')
            {
                result += responseFromServer[p];
                p++;
            }

            result = result.Trim();
            char []array = result.ToCharArray();
            array[0] = Char.ToUpper(array[0]);

            return new string(array);
        }

        /**
         * Returns id of the current submission
         **/
        private int parseSubmissionId(string responseFromServer)
        {
            // Set p to start position of the max_id number
            int p = responseFromServer.IndexOf("max_id") + 15;
            int submission_id = 0;

            while (Char.IsDigit(responseFromServer[p]))
            {
                submission_id = 10 * submission_id + (int)responseFromServer[p] - (int)'0';
                p++;
            }
            return submission_id;
        }

        /**
         * Returns langueage id of the submission langueage
         **/
        private int getLanguageId(string language)
        {
            if (language == "C++") return 41;
            return 41;
        }

        private string createSPOJPostData(int idx)
        {
            // Create post data that has to be sent
            string language = HttpUtility.UrlEncode(getLanguageId(submissions[idx].getLanguage()).ToString());
            string source = HttpUtility.UrlEncode(submissions[idx].getSource());
            string problemId = HttpUtility.UrlEncode(submissions[idx].getRealProblemId());

            string[] data = { "lang=" + language, "file=" + source, "problemcode=" + problemId, "submit=Send", "login_user=" + usernames[idx], "password=" + passwords[idx] };
            return createPostData(data);
        }
    }
}
